
/*! palette-click-force.js
 * Ensure visible feedback on click for color swatches, even under aggressive CSS/CSP.
 * Strategy:
 *  - Event delegation on document (capture phase) so other handlers can't block us
 *  - Toggle a persistent visual state per container
 *  - Apply both a class and inline styles with `!important` to win specificity battles
 *  - No preventDefault/stopPropagation to avoid breaking existing behaviors
 */
(function(){
  const SWATCHES = [
    '#color-search .cb-grid .swatch',
    '#color-board .cb-grid .swatch',
    '#tp-colorboard .cb-grid .swatch',
    '.cb-grid .swatch',
    '.swatches .sw',
    '.swatch',
    '[data-swatch]',
    '[role="swatch"]'
  ];
  const CONTAINERS = ['.cb-grid','.swatches','#color-search','#color-board','#tp-colorboard','[data-swatch-list]'];

  function closestContainer(el){
    for (const s of CONTAINERS){
      const c = el.closest(s);
      if (c) return c;
    }
    return el.parentElement || document.body;
  }
  function qsAll(sel){ try { return Array.from(document.querySelectorAll(sel)); } catch(e){ return []; } }
  function isSwatch(el){
    if (!el) return false;
    for (const s of SWATCHES){
      try{ if (el.matches(s)) return true; }catch(e){}
    }
    return false;
  }
  function findSwatch(target){
    if (!target) return null;
    if (isSwatch(target)) return target;
    for (const s of SWATCHES){
      const x = target.closest(s);
      if (x) return x;
    }
    return null;
  }

  const inline = {
    apply(node){
      try {
        node.style.setProperty('filter', 'brightness(1.08)', 'important');
        node.style.setProperty('transform', 'translateZ(0) scale(1.06)', 'important');
        node.style.setProperty('box-shadow', '0 0 0 2px color-mix(in oklab, var(--primary, #6fe1ff) 70%, #0000) inset, 0 2px 10px rgba(0,0,0,.18)', 'important');
        node.style.setProperty('transition', 'transform .12s ease, filter .12s ease, box-shadow .16s ease', 'important');
      } catch(e){}
    },
    clear(node){
      try {
        node.style.removeProperty('filter');
        node.style.removeProperty('transform');
        node.style.removeProperty('box-shadow');
        // keep transition removal optional
      } catch(e){}
    }
  };

  function selectOne(target){
    if (!target) return;
    const container = closestContainer(target);
    // Clear previous
    container.querySelectorAll('.is-selected').forEach(n => {
      if (n !== target){
        n.classList.remove('is-selected');
        n.setAttribute('aria-pressed','false');
        inline.clear(n);
      }
    });
    // Apply
    target.classList.add('is-selected');
    target.setAttribute('aria-pressed','true');
    inline.apply(target);
  }

  function onClick(ev){
    const t = findSwatch(ev.target);
    if (!t) return;
    selectOne(t);
    // don't block the page's own click handler
  }

  function onKey(ev){
    if (ev.key !== 'Enter' && ev.key !== ' ') return;
    const t = findSwatch(ev.target);
    if (!t) return;
    ev.preventDefault(); // mimic button
    selectOne(t);
    try { t.click(); } catch(e){}
  }

  function init(){
    // Prepare all existing swatches
    const all = [];
    SWATCHES.forEach(s => { all.push(...qsAll(s)); });
    all.forEach(el => {
      if (!el.getAttribute('role')) el.setAttribute('role','button');
      if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex','0');
      el.addEventListener('keydown', onKey, {passive:false});
    });

    // capture-phase click so no one can stopPropagation before we run
    document.addEventListener('click', onClick, true);

    // Mutation observer: if grids render late, we still upgrade them
    const mo = new MutationObserver((muts)=>{
      muts.forEach(m => {
        m.addedNodes && m.addedNodes.forEach(n => {
          if (!(n instanceof Element)) return;
          if (isSwatch(n)){
            if (!n.getAttribute('role')) n.setAttribute('role','button');
            if (!n.hasAttribute('tabindex')) n.setAttribute('tabindex','0');
            n.addEventListener('keydown', onKey, {passive:false});
          }
          // also add for descendants
          SWATCHES.forEach(sel => {
            n.querySelectorAll && n.querySelectorAll(sel).forEach(el => {
              if (!el.getAttribute('role')) el.setAttribute('role','button');
              if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex','0');
              el.addEventListener('keydown', onKey, {passive:false});
            });
          });
        });
      });
    });
    mo.observe(document.documentElement, {childList:true, subtree:true});
  }

  if (document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', init, {once:true});
  } else { init(); }
})();
